#include "stdafx.h"
#include "RecordingSession.h"
#include "PlaybackSession.h"
#include <fstream>

extern CRecordingSession * g_pRecordingSession;
extern CPlaybackSession * g_pPlaybackSession;

BOOL IsMouseMessage(UINT msg)
{
	return msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST;
}

LRESULT CALLBACK JournalRecordProc(int code,WPARAM wparam,LPARAM lparam)
{
	SHORT val=GetKeyState(VK_PAUSE);

	//If Pause/Break key is pressed, stop recording
	//The other key sequence to stop recording, Ctrl+Esc automatically evicts the hook
	//so all we have to do is update the UI accordingly, that code is there in
	//the GetMsgProc function
	if (val & 0x80000000)
	{
		LRESULT result = CallNextHookEx(g_pRecordingSession->GetHookHandle() ,code, wparam, lparam);
		g_pRecordingSession->SessionCancelled();
		return result;
	}

	EVENTMSG *mesg = NULL;
	switch (code)
	{
	case HC_ACTION:
		//The main part. HC_ACTION is called whenever there is a mouse or keyboard event.
		//lparam is a pointer to EVENTMSG struct, which contains the necessary information
		//to replay the message.
		mesg = (EVENTMSG *) lparam;

		if (g_pRecordingSession->AreMouseActionsIgnored() && IsMouseMessage(mesg->message))
		{
			// Ignore the mouse message
		}
		else
		{
			g_pRecordingSession->AppendToFile(mesg);
		}
		break;
	}

	return CallNextHookEx(g_pRecordingSession->GetHookHandle(), code, wparam, lparam);
}

LRESULT CALLBACK JournalPlaybackProc(int code,WPARAM wparam,LPARAM lparam)
{
	//To compute how much we need to sleep
	LRESULT delta;

	//The playback callback hook function
	//Log("Outside switch");
	EVENTMSG *msg = NULL;
	switch(code)
	{
	case HC_GETNEXT:
		{
			//Like JournalRecordProc, this function also has the lparam, except that we must
			//supply the EVENTMSG structure. The system then rthe lparam, and uses the
			//info in the EVENTMSG to replay the message.

			msg=(EVENTMSG *)lparam;

			EVENTMSG msg_from_file = g_pPlaybackSession->GetCurrentMessage();

			msg->hwnd = msg_from_file.hwnd ;
			msg->message = msg_from_file.message ;
			msg->paramH = msg_from_file.paramH ;
			msg->paramL = msg_from_file.paramL ;
			msg->time = msg_from_file.time;

			//This measures the difference between when mesg is to played and current time.
			delta = msg->time - GetTickCount();

			//If more than zero (ie msg is to played some time in the future)
			// return that time. The system sleeps for that time, before
			//calling HC_GETNEXT again, in which case, delta will be <=0, and we return 0.
			//The system then plays that message.
			if (delta > 0)
			{
				return delta;
			}
			else
			{
				return 0;
			}
		}

		////HC_GETNEXT can be called as many times as the system wants, we have to supply the
		////same message. Only when HC_SKIP is called, we can advance to the next message in our
		////file. move_next is the BOOL variable that takes care of this.
		//if (move_next)
		//{

		//	//If no repeat and we have not reached EOF
		//	//or with repeat and repeat_index has not yet reached repeatcount
		//	if (next_message_exists)
		//	{


		//		//Read next message
		//		//From file if we are playing back the first time
		//		if (repeat_index==0)
		//		{
		//			prev_mesg_from_file = mesg_from_file;

		//			input->read((char *)&mesg_from_file,sizeof(EVENTMSG));
		//			//If this is EOF, reset next_message_exists
		//			if (input->eof()) next_message_exists=FALSE;


		//			//Add it message list so that we can use this as cache
		//			//Only if we need to repeat playback
		//			if (repeat_count)
		//			{
		//				message_list->AddTail(mesg_from_file);
		//			}
		//		}
		//		//We're playing back from the list now.
		//		else
		//		{
		//			//If we've not reached the end of the list
		//			if (list_position!=NULL)
		//			{
		//				prev_mesg_from_file = mesg_from_file;
		//				//Read next struct
		//				mesg_from_file=message_list->GetNext(list_position);
		//			}
		//			else
		//			{
		//				next_message_exists=FALSE;
		//			}

		//		}	

		//	}
		//	else
		//	{
		//		//We have played back all messages and that's why next_message_exists
		//		//had been set to false. 

		//		//If we've repeated playback enough times
		//		if (repeat_index>=repeat_count)
		//		{
		//			//Remove the hook, close the file handle
		//			//and reset playing_back, 
		//			uninstall_playback_hook();
		//			MessageBox(thiswindow_hwnd,"Playback Over","WinMacro v1.2",MB_OK|MB_ICONEXCLAMATION);
		//			return 0;
		//		}
		//		else
		//		{
		//			repeat_index++;


		//			//Re initialize start_time to current tick count so that messages can be played back
		//			//with the same delays between them.
		//			start_time=GetTickCount();

		//			//Reset everything else
		//			prev_message_tick_count = 0;
		//			prev_mesg_from_file = EVENTMSG();
		//			mesg_count=0;
		//			move_next=TRUE;
		//			next_message_exists=TRUE;

		//			//Initialize list position to start of list
		//			list_position=message_list->GetHeadPosition();

		//			//Clear Keyboard state (remove control,alt or other key presses)
		//			BYTE keyboard_state[256];
		//			GetKeyboardState(keyboard_state);
		//			keyboard_state[VK_CONTROL]=keyboard_state[VK_CONTROL] & 0x00000000;
		//			keyboard_state[VK_MENU]=keyboard_state[VK_MENU] & 0x00000000;

		//			SetKeyboardState(keyboard_state);


		//			//Set flag variable to indicate we are playing back.  This is needed because a click to the "Stop Recording" button 
		//			//of this application is also stored when recording. When the file is played back, that button gets clicked again, but this 
		//			//time "Start Recording" gets clicked,(because it's playing back, not recording). This unfortunately causes recording to begin
		//			//again. Took lots of time to figure this out :)
		//			playing_back=TRUE;

		//		}
		//		return 0;
		//	}

		//	//This is so that the same message is sent, until HC_SKIP is called
		//	move_next=FALSE;

		//}

		////Copy mesg from file to the lparam structure (which has been typecast)
		//mesg->hwnd=mesg_from_file.hwnd ;
		//mesg->message=mesg_from_file.message ;
		//mesg->paramH=mesg_from_file.paramH ;
		//mesg->paramL=mesg_from_file.paramL ;

		////Whatever the option (user defined interval or normal)
		////initialize mesg time with start_time
		////if user defined, add it with the specified time times mesg count
		////Simply supplying time_interval is not going to work because it then adds time_interval
		////with every event, resulting in only the first event getting delayed by time_interval,
		////For eg, Assuming constant time_interval of 50
		////if start_time is 100, then first message is fired at 150
		////so a delay of 50 is there.Current time now becomes 150. Now next message is also fired at
		////150, it never goes past that. So we multiply time_interval with mesg_count, so the second
		////message is scheduled at 100+2*50 or 200, so that at 150, a delay of 50 (200-150) is created.
		////aaaaaah. Relax now.

		//mesg->time = (prev_message_tick_count == 0 ? start_time : prev_message_tick_count)
		//	+time_interval*mesg_count;

		////Check whether user has selected normal speed or given his own speed
		//if (normal_speed || add_to_recorded_time )
		//{
		//	//If playing at normal speed or if time_interval is to be added to recorded time
		//	//add it with time from the stored message from file.
		//	mesg->time += (mesg_from_file.time - prev_mesg_from_file.time);
		//	Log(mesg->time);			

		//}

		////This measures the difference between when mesg is to played and current time.

		//delta=mesg->time-GetTickCount();

		////If more than zero (ie mesg is to played some time in the future)
		//// return that time. The system sleeps for that time, before
		////calling HC_GETNEXT again, in which case, delta will be <=0, and we return 0.
		////The system then plays that message.
		//if (delta>0)
		//{
		//	Log(delta);			
		//	return delta;
		//}
		//else
		//{
		//	Log((DWORD)0);
		//	return 0;
		//}

		break;

	case HC_SKIP:
		g_pPlaybackSession->MoveNext();

		if (g_pPlaybackSession->IsCurrentMessageAvailable() == false)
		{
			//Clear Keyboard state (remove control,alt or other key presses)
			BYTE keyboard_state[256];
			GetKeyboardState(keyboard_state);
			keyboard_state[VK_CONTROL]=keyboard_state[VK_CONTROL] & 0x00000000;
			keyboard_state[VK_MENU]=keyboard_state[VK_MENU] & 0x00000000;

			SetKeyboardState(keyboard_state);

			g_pPlaybackSession->SessionCancelled();
		}
		break;
	default:
		return CallNextHookEx(g_pPlaybackSession->GetHookHandle(), code, wparam, lparam);
	}
	//System ignores this. Just to satisfy the compiler.
	return 0;
}
